/*--------------------------------------------------------------------------
    This source file is part of Abraxas Game Engine
    For the latest info, see http://code.google.com/abraxasge/
    Copyright (C) 2009, Andrew LeRoy <aleroy@member.igda.org>
    ---

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA  02110-1301, USA.
--------------------------------------------------------------------------*/
#include "AbxDynamicLibrary.hpp"

#include "AbxStdHeaders.hpp"
#include "AbxException.hpp"
#include "AbxLogManager.hpp"

#if ABX_PLATFORM == ABX_PLATFORM_WIN32
#   define WIN32_LEAN_AND_MEAN
#   include <windows.h>
#endif

#if ABX_PLATFORM == ABX_PLATFORM_APPLE
#   include "macPlugins.h"
#endif


namespace Abx
{
    DynamicLibrary::DynamicLibrary(String const& name )
    {
        mName = name;
        m_hInst = NULL;
    }

    //-----------------------------------------------------------------------
    DynamicLibrary::~DynamicLibrary()
    {
    }

    //-----------------------------------------------------------------------
    void DynamicLibrary::load()
    {
        // Log library load
        LogManager::Instance().logMessage("Loading library " + mName);

        String name = mName;
#if ABX_PLATFORM == ABX_PLATFORM_LINUX
        // dlopen() does not add .so to the filename, like windows does for .dll
        if (name.substr(name.length() - 3, 3) != ".so")
           name += ".so";
#endif

        m_hInst = (DYNLIB_HANDLE)DYNLIB_LOAD( name.c_str() );

        if( !m_hInst )
            ABX_EXCEPT(
                Exception::ERR_INTERNAL_ERROR, 
                "Could not load dynamic library " + mName + 
                ".  System Error: " + dynlibError(),
                "DynLib::load" );
    }

    //-----------------------------------------------------------------------
    void DynamicLibrary::unload()
    {
        // Log library unload
        LogManager::Instance().logMessage("Unloading library " + mName);

        if( DYNLIB_UNLOAD( m_hInst ) )
        {
            ABX_EXCEPT(
                Exception::ERR_INTERNAL_ERROR, 
                "Could not unload dynamic library " + mName +
                ".  System Error: " + dynlibError(),
                "DynLib::unload");
        }

    }

    //-----------------------------------------------------------------------
    void* DynamicLibrary::getSymbol(String const& strName) const throw()
    {
        return (void*)DYNLIB_GETSYM( m_hInst, strName.c_str() );
    }

    //-----------------------------------------------------------------------
    String DynamicLibrary::dynlibError(void) 
    {
#if ABX_PLATFORM == ABX_PLATFORM_WIN32
        LPVOID lpMsgBuf; 
        FormatMessage( 
            FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM | 
            FORMAT_MESSAGE_IGNORE_INSERTS, 
            NULL, 
            GetLastError(), 
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
            (LPTSTR) &lpMsgBuf, 
            0, 
            NULL 
            ); 
        String ret = (char*)lpMsgBuf;
        // Free the buffer.
        LocalFree(lpMsgBuf);
        return ret;
#elif ABX_PLATFORM == ABX_PLATFORM_LINUX
        return String(dlerror());
#elif ABX_PLATFORM == ABX_PLATFORM_APPLE
        return String(mac_errorBundle());
#else
        return String("");
#endif
    }
    
} // namespace Abx
